package com.hero.herocat;

import com.hero.servlet.HeroRequest;
import com.hero.servlet.HeroServlet;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpRequest;

import java.util.Map;

/**
 * HeroCat服务端处理器
 * 1）从用户请求URI中解析出要访问的Servlet名称
 * 2）从nameToServletMap 中查找是否存在该名称的key，若存在，则直接使用该实例。，否则执行第 3）步。
 * 3）从nameToClassNameMap中查找是否存在该名称的key，若存在，则直接获取到其对应的全限定类名，
 * 使用反射机制创建相应的servlet实例，并写入到nameToServletMap中，若不存在，则直接访问默认Servlet
 */
public class HeroCatHandler extends ChannelInboundHandlerAdapter {

    private Map<String, HeroServlet> nameToServletMap; // 线程安全 servlet--> 对象
    private Map<String, String> nameToClassNameMap; // 线程不安全  servlet --> 全限定名称

    public HeroCatHandler(Map<String, HeroServlet> nameToServletMap, Map<String, String> nameToClassNameMap) {
        this.nameToServletMap = nameToServletMap;
        this.nameToClassNameMap = nameToClassNameMap;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // instanceof 左边的对象是否是它右边的类的实例，返回 boolean 的数据类型。
        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;
            String uri = request.uri();

            // 从请求汇总解析出要访问的Servlet名称
            // aaa/bbb/ccc/twoServlet?name=liu
            String servletName = "";
            if (uri.contains("?") && uri.contains("/")) {
                servletName = uri.substring(uri.lastIndexOf("/") + 1, uri.indexOf("?"));

            }
            HeroServlet servlet = new DefaultHeroServlet();
            // 第一次访问，Servlet是不会被加载的
            // 初始化加载的只是类全限定名称，懒加载
            // 如果访问Servlet才回去初始化它的对象
            if (nameToServletMap.containsKey(servletName)) {
                servlet = nameToServletMap.get(servletName);
            } else if (nameToServletMap.get(servletName) == null) {
                // double-check，双重检测锁：为什么要在锁前判断一次，还要在锁后继续判断一次？
                synchronized (this) {
                    if (nameToServletMap.get(servletName) == null) {
                        // 获取当前Servlet的全限定类名
                        String className = nameToClassNameMap.get(servletName);
                        // 使用反射机制创建Servlet实例
                        servlet = (HeroServlet) Class.forName(className).newInstance();
                        // 将Servlet写入到nameToServletMap
                        nameToServletMap.put(servletName, servlet);
                    }
                }
            }
            // 代码走到这里，servlet肯定不为空
            HeroRequest req = new HttpHeroRequest(request);
            HttpHeroResponse response = new HttpHeroResponse(request, ctx);
            // 根据不同的请求类习惯，调用servlet实例的不同方法;
            if (request.method().name().equalsIgnoreCase("GET")) {
                servlet.doGet(req, response);
            } else if (request.method().name().equalsIgnoreCase("POST")) {
                servlet.doPost(req, response);
            }
            ctx.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
